<template>
	<!-- 表单 -->
	<el-form-item
		:class="{'hided-label': !showLabel,'is-disabled': disabled, 'is-txt': showText}"
		:label="label"
		:label-width="labelWidth || '120px'"
		:prop="prop"
		:rules="ruleArr"
		:style="{width}"
		v-if="!hide"
	>
		<!-- 输入框、数字、文本域 -->
		<el-input
			:autosize="{minRows:4}"
			:disabled="formItemDisabled"
			:maxlength="maxlength || 100"
			:placeholder="itemPlaceholder"
			:rows="rows || 1"
			:type="type === 'textarea' ? type : 'input'"
			@input="uploadVal"
			@keyup.enter.native="keyupEnterFun"
			clearable
			resize="none"
			v-if="type === 'input' || type === 'number' || type === 'textarea'"
			v-model="formValue"
		>
			<template
				slot="append"
				v-if="unit"
			>{{unit}}</template>
		</el-input>
		<!-- 手机号 -->
		<el-input
			:disabled="formItemDisabled"
			:maxlength="11"
			:placeholder="itemPlaceholder"
			@input="uploadVal"
			@keyup.enter.native="keyupEnterFun"
			v-else-if="type === 'phone'"
			v-model="formValue"
		/>
		<!-- 下拉框 -->
		<el-select
			:disabled="formItemDisabled"
			:filterable="filterable"
			:multiple="multiple"
			:placeholder="itemPlaceholder"
			:popper-class="popperClassName"
			@change="uploadVal"
			clearable
			v-else-if="type === 'select'"
			v-model="formValue"
		>
			<el-option
				:key="item[selectValue] + idx"
				:label="item[selectLabel]"
				:value="item[selectValue]"
				v-for="(item, idx) in optionsList"
			>
				<!-- 选项前面的 圆圈 -->
				<span
					:style="'--color:'+item.color"
					class="option-circle"
					v-if="item.color"
				></span>
				<span>{{ item[selectLabel] }}</span>
			</el-option>
		</el-select>
		<!-- 级联选择器 -->
		<el-cascader
			:disabled="formItemDisabled"
			:filterable="filterable"
			:options="optionsList"
			:placeholder="itemPlaceholder"
			:popper-class="popperClassName"
			:props="propsObj"
			:show-all-levels="showAllLevels"
			@change="uploadVal"
			clearable
			ref="cascader"
			v-else-if="type === 'cascader'"
			v-model="formValue"
		/>
		<!-- 时间选择 -->
		<template v-else-if="type === 'date'">
			<!-- TODO: 后期优化（详情显示提取到其他组件去） -->
			<p
				class="show-txt"
				v-if="showText"
			>{{Array.isArray(formValue) ? formValue[0] ? formValue.join('至') : emptyTxt : formValue || emptyTxt}}</p>
			<el-date-picker
				:disabled="formItemDisabled"
				:format="valueFormat || defaultFormatDate"
				:picker-options="pickerOptions || (dateType === 'daterange' ? defaultDateIntervalOptions : defaultDateOptions)"
				:placeholder="itemPlaceholder"
				:type="dateType || 'date'"
				:unlink-panels="unlinkPanels"
				:value-format="valueFormat || defaultFormatDate"
				@change="uploadVal"
				clearable
				end-placeholder="结束日期"
				range-separator="至"
				start-placeholder="开始日期"
				v-else
				v-model="formValue"
			></el-date-picker>
		</template>
		<!-- 评分 -->
		<el-rate
			:disabled="formItemDisabled"
			:max="3"
			@change="uploadVal"
			v-else-if="type === 'rate'"
			v-model="formValue"
		/>
		<!-- 进度条 -->
		<div
			class="progress-wrap"
			v-else-if="type === 'progress'"
		>
			<el-progress :percentage="formValue"></el-progress>
			<el-input-number
				:max="100"
				:min="0"
				:step="2"
				@change="uploadVal"
				v-model="formValue"
			/>
		</div>
		<!-- 单选框 -->
		<el-radio-group
			:disabled="formItemDisabled"
			@change="uploadVal"
			v-else-if="type === 'radio'"
			v-model="formValue"
		>
			<el-radio
				:key="item[selectValue]"
				:label="item[selectValue]"
				v-for="item in optionsList"
			>{{item[selectLabel]}}</el-radio>
		</el-radio-group>
		<!-- 上传 -->
		<div
			class="progress-wrap"
			v-else-if="type === 'upload'"
		>
			<OssUpload
				class="oss-upload"
				v-model="formValue"
				@input="uploadVal"
			></OssUpload>
		</div>
		<!-- 数字区间输入 -->
		<div
			class="flex-row"
			v-if="type === 'numberInterval'"
		>
			<el-input-number
				:controls="false"
				:disabled="formItemDisabled"
				:min="0"
				@change="numberIntervalChange($event, 0)"
				@keyup.enter.native="keyupEnterFun"
				class="mr-10"
				placeholder="最小值"
				v-model="minimum"
			/>至
			<el-input-number
				:controls="false"
				:disabled="formItemDisabled"
				:min="0"
				@change="numberIntervalChange($event, 1)"
				@keyup.enter.native="keyupEnterFun"
				class="ml-10"
				placeholder="最大值"
				v-model="maximum"
			/>
		</div>
		<!-- 带输入建议输入框 -->
		<el-autocomplete
			:fetch-suggestions="fetchSuggestions"
			:placeholder="itemPlaceholder"
			@keyup.enter.native="keyupEnterFun"
			@select="uploadVal"
			clearable
			v-else-if="type === 'suggestionInput'"
			v-model="formValue"
		></el-autocomplete>
		<!-- 点击框 -->
		<div
			@click="clickFun"
			class="el-input el-input--small el-input--suffix"
			v-else-if="type === 'click'"
		>
			<input
				:placeholder="itemPlaceholder"
				:value="formValue"
				class="el-input__inner"
				disabled
				style="pointer-events: none"
				type="text"
			/>
		</div>
		<slot name="suffix" />
	</el-form-item>
</template>

<script>
	import { defaultDateOptions, defaultDateIntervalOptions } from './data'
	// import Upload from '@/components/Upload'
	import { isObject, isArray, isEmptyVal } from '@/utils/base/type'
	import regExpList from '@utils/base/regExp'

	const types = {
		click: { defaultValue: '', defaultPlaceholder: '请选择' },
		input: { defaultValue: '', defaultPlaceholder: '请输入' },
		number: { defaultValue: null, defaultPlaceholder: '请输入' },
		phone: { defaultValue: null, defaultPlaceholder: '请输入' },
		select: { defaultValue: '', defaultPlaceholder: '请选择' },
		cascader: { defaultValue: [], defaultPlaceholder: '请选择' },
		textarea: { defaultValue: '', defaultPlaceholder: '请输入' },
		date: { defaultValue: '', defaultPlaceholder: '请选择' },
		radio: { defaultValue: null, defaultPlaceholder: '请选择' },
		rate: { defaultValue: 0, defaultPlaceholder: '请选择' },
		progress: { defaultValue: 0, defaultPlaceholder: '请选择' },
		numberInterval: { defaultValue: [], defaultPlaceholder: '请输入' },
		suggestionInput: { defaultValue: '', defaultPlaceholder: '请输入' }
	}
	export default {
		model: {
			prop: 'value',
			event: 'change'
		},
		props: {
			// 是否隐藏
			hide: Boolean,
			// 字段key
			prop: String,
			// 表单文字
			label: String,
			// 表单value
			value: [String, Number, Array, Date, Boolean],
			// 是否必填
			required: Boolean,
			// 校验规则
			rules: [Object, Array],
			// 是否可编辑
			disabled: Boolean,
			// 是否显示label
			showLabel: {
				type: Boolean,
				default: true
			},
			// label宽度
			labelWidth: String,
			// 表单宽度
			width: {
				type: String,
				default: '33%'
			},
			// 表间类型 types.keys()
			type: {
				type: String,
				default: 'input'
			},
			// 提示
			placeholder: String,
			// 处理值函数
			dealValFun: Function,
			// 是否只显示文本
			showText: Boolean,
			emptyTxt: {
				type: String,
				default: '未填'
			},

			// 单位（输入框）
			unit: String,
			// 输入框最大限制（输入框、文本域）
			maxlength: Number,
			// 行数(文本域)
			rows: Number,
			// 是否是整型数字
			isInt: Boolean,

			// 选择器label和value(级联 、 选择器 和 单选)
			selectLabel: {
				type: String,
				default: 'label'
			},
			selectValue: {
				type: String,
				default: 'value'
			},
			// 是否显示全部等级(级联)
			showAllLevels: {
				type: Boolean,
				default: true
			},
			// 是否多选（级联 和 单选）
			multiple: Boolean,
			// 控件参数值（级联）
			props: Object,
			// 表单选项（级联 和 选择器）
			options: [Array, Promise],
			// 可以利用搜索功能快速查找选项(级联 和 选择器)
			filterable: {
				type: Boolean,
				default: true
			},
			// 多级选项 弹出层类名(选择器, 级联)
			popperClassName: String,

			// 快捷键选项（日期选择器）
			pickerOptions: Object,
			// 日期类型（日期选择器）
			dateType: String,
			valueFormat: String,
			// 在范围选择器里取消两个日期面板之间的联动(日期选择器)
			unlinkPanels: Boolean,

			// 输入时调用拿取数据函数(带输入建议)
			querySearch: Function,

			// 点击回调函数（点击表单）
			clickFun: Function
		},
		data() {
			return {
				// 选一个时间时选项
				defaultDateOptions,
				// 选区间时间时选项
				defaultDateIntervalOptions,

				optionsList: [],
				// 表单值
				formValue: this.getValue(),

				minimum: undefined,
				maximum: undefined
			}
		},
		watch: {
			value(val) {
				// radio特殊处理
				// 处理radio 选择了还是校验不通过的bug
				if (this.type === 'radio' && val) this.$children[0].clearValidate()

				if (this.formValue !== val) this.formValue = this.getValue()
			},
			formValue(val, oldVal) {
				// suggestionInput特殊处理
				// 带输入建议输入框特殊处理，因为事件监听无效
				if (this.type === 'suggestionInput') {
					this.uploadVal({ value: val })
				}
			},
			// 监听选项改变
			options() {
				this.changeOptions()
			}
		},
		// components: { Upload },
		computed: {
			// 表单组件是否禁用
			formItemDisabled() {
				return this.disabled || this.showText
			},
			// 表单placeholder
			itemPlaceholder() {
				return this.showText ? this.emptyTxt : this.placeholder || types[this.type]?.defaultPlaceholder + this.label
			},
			// 规则数组
			ruleArr() {
				// 规则校验数组初始化（当前是否传入校验规则，是数组还是对象）
				const rules = isObject(this.rules) ? [this.rules] : isArray(this.rules) ? this.rules : []
				// 当前是否是必填字段（传入true 或者 没传 是必填）
				if (this.required === true) {
					rules.push({ required: true, message: this.label + '不能为空', trigger: 'change' })
				}
				if (this.type === 'phone') {
					rules.push({ pattern: regExpList.isPhone, message: '请输入正确的手机号', trigger: 'blur' })
				}
				return rules
			},
			// 级联选项
			propsObj() {
				const defaultProps = { multiple: this.multiple, emitPath: false, label: this.selectLabel, value: this.selectValue }
				return Object.assign(defaultProps, this.props)
			},
			defaultFormatDate() {
				if (this.type !== 'date') return
				return this.dateType === 'year' ? 'yyyy' : 'yyyy-MM-dd'
			}
		},
		created() {
			this.changeOptions()
		},
		methods: {
			// 获取当前值
			getValue() {
				let val = this.value ?? types[this.type]?.defaultValue
				// 将单选字段值 由数字 转为 字符串
				if (this.type === 'radio' && typeof val === 'number') val = val?.toString()
				// 如果 只显示文本，并且有单位，需要将 值和单位拼接
				if (this.showText && !isEmptyVal(val) && this.unit) val = val + this.unit
				return val
			},
			// 修改选项（级联 和 选择器）
			changeOptions() {
				if (this.options instanceof Promise) {
					this.options.then(data => (this.optionsList = data))
				} else if (this.type === 'radio' && !this.options) {
					this.optionsList = [
						{ [this.selectLabel]: '是', [this.selectValue]: '1' },
						{ [this.selectLabel]: '否', [this.selectValue]: '0' }
					]
				} else {
					this.optionsList = this.options || []
				}
			},
			// 回车事件
			keyupEnterFun() {
				this.$emit('keyupEnterFun')
			},
			// TODO: 后面干掉，现在有地方引用
			// 获取cascader选中的label
			getCascaderValLabel() {
				return this.$refs.cascader.getCheckedNodes()[0].pathLabels
			},
			// 更新value
			async uploadVal(val) {
				if (this.type === 'number' || this.type === 'phone') {
					// 数字 或者 电话
					val = this.isInt || this.type === 'phone' ? val.replace(/[^\d]*/g, '') : val.replace(/[^\d.]*/g, '').replace(/(\.\d*)\./, '$1')
					this.formValue = val
				} else if (this.type === 'suggestionInput') {
					// 带输入建议输入框
					val = val.value
				} else if (this.type === 'cascader' && !(this.props?.multiple || this.multiple)) {
					// 单选级联 选择后关闭
					this.$refs.cascader.dropDownVisible = false
				}
				// 是否传入 值的处理函数
				if (this.dealValFun) {
					this.formValue = val = (await this.dealValFun(val, this)) || val
				}
				this.$emit('change', val, this.prop)
			},
			// 数字区间值改变（区间输入）
			numberIntervalChange(val, position) {
				if (!Array.isArray(this.formValue)) this.formValue = []
				this.formValue[position] = val
				this.$emit('change', this.formValue, this.prop)
			},
			// 带建议的输入框回调函数（带建议的输入）
			fetchSuggestions(queryString, cb) {
				if (this.querySearch) {
					// cb第一个参数是返回结果
					this.querySearch(queryString, cb)
				} else {
					const arr = []
					if (cb) cb(arr)
				}
			},
			// 重置表单
			resetFields() {
				// 数字区间输入重置
				if (this.type === 'numberInterval') {
					this.minimum = undefined
					this.maximum = undefined
				}
				// 重置默认值
				this.formValue = types[this.type]?.defaultValue
				this.$emit('change', this.formValue, this.prop)
			}
		}
	}
</script>
<style lang="scss" scoped>
	.el-form-item::v-deep {
		display: inline-block;
		&.hided-label {
			.el-form-item__label {
				display: none;
			}
			.el-form-item__content {
				margin-left: 20px !important;
			}
		}
		.el-autocomplete {
			display: block;
		}
		&.is-txt {
			.el-form-item__content {
				// pointer-events: none;
				.el-textarea__inner,
				.el-input__inner,
				.el-range-input,
				.show-txt {
					border: none;
					background-color: transparent !important;
					color: #666;
					&::-webkit-input-placeholder {
						color: #000;
					}
				}
				.el-input__icon {
					display: none;
				}
			}
			.el-input-group__append {
				border: 0;
			}
			.el-input-group__append {
				display: none;
			}
		}
	}

	.el-input-number::v-deep {
		width: 100%;
		.el-input__inner {
			text-align: left;
		}
	}
	.el-cascader,
	.el-date-editor,
	.el-select {
		width: 100%;
	}

	.el-rate {
		display: inline-block;
		vertical-align: middle;
	}

	.progress-wrap::v-deep {
		display: flex;
		align-items: center;
		.el-progress {
			flex: 1;
			.el-progress-bar {
				padding-right: 70px;
				margin-right: -70px;
			}
		}
		.el-input-number {
			width: 120px !important;
			.el-input__inner {
				text-align: center !important;
			}
		}
	}
	.option-circle {
		display: inline-block;
		width: 10px;
		height: 10px;
		background: var(--color);
		border-radius: 10px;
		margin-right: 10px;
	}
	.is-disabled::v-deep .el-upload-dragger {
		background-color: #eee;
		cursor: not-allowed;
	}
</style>
